<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.js"></script>
</head>
<body>
  <button id="btn">test</button>
<!-- 
js代码的整体执行顺序:
  script看作第一个宏任务:  (一个宏任务 => 所有微任务)
  不将script看作第一个宏任务: sciprt同步代码 => (所有微任务 => 第一个宏任务)

  在点击回调或定时器回调中执行过程中, 启动一个宏任务和一个微任务   微任务先执行  => 微任务优先级高于宏任务

事件循环机制
  这个机制中除了堆空间和执行栈, 还有2个重要结构:
    在分线程执行的管理模块: 定时器的/ajax的/dom事件的
    存储待执行回调函数的队列: 宏队列和微队列
  一上来先执行script中的同步代码, 这其中包含了一些启动异步任务的代码
  启动异步任务:
    启动定时器: 将回调函数和时间交给定时器管理模块
    发ajax: 将回调函数交给ajax管理模块
    绑定事件:  将回调函数交给dom事件管理模块
  当达到条件(时间到了/请求返回了/dom事件触发了)
    将回调函数添加到宏队列, 等待执行
  当script中的同步代码执行完后, 就会遍历取出宏队列中的回调依次执行

  如果执行同步代码过程中启动微任务, 将对应的回调添加到微列表中, 
  在执行每个宏队列中的第一个宏任务之前, 都会先遍历取出所有微任务回调执行

 -->

<script> // 第一次宏任务  => 但它不进入宏队列, 是第一个执行的任务   初始化同步代码
  function fn1() {
    setTimeout(() => { // 宏任务
      console.log('timeout callback');
    }, 1000);
    // 如果启动定时器后的同步任务需要花的时间超过延迟的时间, 定时器就不能定时执行了
  }

  function fn2() {
    document.getElementById('btn').onclick = function () { // 宏任务
      console.log('dom event callback');
    };
  }

  function fn3() {
    $.get('./08_product.json', (data) => {  // 宏任务
      console.log('ajax callback', data);
      Promise.resolve(1).then(() => { // 微任务
        console.log('Promise 回调3');
      });
    });
  }

  function fn4() {   // 同步任务
    console.log('同步任务');
    for (let index = 0; index < 100000; index++) {}
  }

  function fn5() {  
    Promise.resolve(1).then(() => { // 微任务
      console.log('Promise 回调1');
    });
    Promise.resolve(2).then(() => { // 微任务
      console.log('Promise 回调2');
    });
  }

  fn1();
  fn2();
  fn3();
  fn4();
  fn5();
</script>
</body>
</html>